<?php

namespace catchAdmin\wechatopen\model;

use catchAdmin\permissions\model\UserHasGroupTrait;
use catcher\base\CatchModel as Model;
use EasyWeChat\Kernel\Exceptions\DecryptException;
use Exception;
use Godruoyi\Snowflake\Snowflake;
use catchAdmin\wechatopen\service\TokenService;
use EasyWeChat\MiniProgram\Encryptor;
use think\facade\Log;

/**
 *
 * @property int $id
 * @property string $user_ids
 * @property string $appid
 * @property string $openid
 * @property string $unionid
 * @property string $nickname
 * @property string $phoneNumber
 * @property string $purePhoneNumber
 * @property string $countryCode
 * @property string $password
 * @property int $gender
 * @property string $city
 * @property string $province
 * @property string $country
 * @property string $avatarUrl
 * @property string $language
 * @property int $subscribe
 * @property int $subscribe_time
 * @property string $remark
 * @property string $tagid_list
 * @property string $subscribe_scene
 * @property string $qr_scene
 * @property string $qr_scene_str
 * @property string $privilege
 * @property string $loginip
 * @property string $token
 * @property string $status
 * @property string $access_token
 * @property string $access_token_overtime
 * @property string $session_key
 * @property string $verification
 * @property int $created_at
 * @property int $updated_at
 * @property int $deleted_at
 * @property int $creator_id
 */
class WechatopenMiniappUsers extends Model
{
    use UserHasGroupTrait;
    // 表名
    public $name = 'wechatopen_miniapp_users';
    // 数据库字段映射
    public $field = array(
        'id',
        // 关联管理后台users表ID
        'user_ids',
        // 关联applet表appid
        'appid',
        // openid
        'openid',
        // 用户统一标识
        'unionid',
        // 用户昵称
        'nickname',
        // 用户绑定的手机号（国外手机号会有区号）
        'phoneNumber',
        // 没有区号的手机号
        'purePhoneNumber',
        // 区号
        'countryCode',
        // 登录密码
        'password',
        // 性别:1=男,2=女,0=未知
        'gender',
        // 城市
        'city',
        // 省份
        'province',
        // 国家
        'country',
        // 头像
        'avatarUrl',
        // 语言
        'language',
        // 是否使用该小程序标识，0=未关注，1=关注
        'subscribe',
        // 使用时间
        'subscribe_time',
        // 运营者对粉丝的备注
        'remark',
        // 用户被打上的标签ID列表
        'tagid_list',
        // 用户使用的渠道来源
        'subscribe_scene',
        // 二维码扫码场景（开发者自定义）
        'qr_scene',
        // 二维码扫码场景描述（开发者自定义）
        'qr_scene_str',
        // 用户特权信息，json数组
        'privilege',
        // ip地址
        'loginip',
        // token,自定义登录态请求api的标识，前端需缓存
        'token',
        // 状态
        'status',
        // access_token
        'access_token',
        // access_token过期时间
        'access_token_overtime',
        // 会话密钥
        'session_key',
        // 验证
        'verification',
        // 创建时间
        'created_at',
        // 更新时间
        'updated_at',
        // 软删除字段
        'deleted_at',
        // 创建人ID
        'creator_id',
    );

    /**
     * 微信小程序保存令牌
     * @access public
     * @param array $sessionData  需要更新的session_key,如果无需更新可传空数组[]
     * @param boolean  $refresh   是否刷新token和session_key
     * @return array  粉丝信息
     */
    public function refreshToken($sessionData ,$refresh = true)
    {
        // 写入登录Session和Token
        $user = self::where('openid',$sessionData['openid'])->find();
        if($refresh){  //更新token和session_key
            $this->save([
                'prevtime'  => $user['logintime'],
                'logintime' => time(),
                'loginip'   => request()->ip(),
                'access_token'    => isset($sessionData['session_key'])? $sessionData['session_key'] : '', //session_key保存成了access_token字段
                'token'    => isset($sessionData['session_key'])? $sessionData['session_key'] : '', //session_key保存成了access_token字段
                'access_token_overtime'    => time() + 3*24*3600, //和token字段生命周期相同
                'union_id'    => isset($sessionData['unionid'])? $sessionData['unionid'] : '',  //我也不知道为啥我又把unionID写回，换了开放平台unionid会变
            ],['openid' => $sessionData['openid']]);
            $faToken = Token::set(isset($sessionData['session_key'])? $sessionData['session_key'] : '',$user->id,time() + 3*24*3600);
            $getfaToken = Token::get(isset($sessionData['session_key'])? $sessionData['session_key'] : '');
        }else{
            $this->save([
                'prevtime'  => $user['logintime'],
                'logintime' => time(),
                'loginip'   => request()->ip(),
            ],['openid' => $sessionData['openid']]);
        }
    }

    /**
     * 微信小程序用户登录
     * @access public
     * @param string $appid   appid
     * @param string $openId   粉丝openid
     * @param array  $sessionData   包含 session_key,openid,unionid（符合unionid条件时）
     * @return array  粉丝信息
     */
    public function loginByOpenId($appid,$openId, $sessionData = null)
    {
        if(empty($openId))
            return ['code'=>400,'msg'=>'OpenID不能为空'];
        $user = self::where('openid',$openId)->find();

        if(empty($user))  //用openid初始化一个匿名粉丝帐号，表示到此一游
        {
            //数据表中字段和微信接口字段不一样，还得重整一下，擦！
            $ip = request()->ip();
            $time = time();
            $user_ids = input('user_ids');  //如果前端传入了user_ids的值，则添加小程序用户与后台管理员的关联。随缘添加
            if($user_ids){
                $data['user_ids'] = $user_ids;
            }
            $data['appid'] = $appid;
            $data['openid'] = $sessionData['openid'];
            $data['gender'] = 0;
            $data['subscribe'] = 1;
            $data['subscribe_time'] = $time;
            $data['session_key'] = isset($sessionData['session_key'])? $sessionData['session_key'] : '';
            $snowflake = new Snowflake;
            $data['token'] =  $snowflake->id();               //自定义登录态
            $data['access_token_overtime'] = time() + 3*24*3600; //和token字段生命周期相同
            $data['unionid'] = isset($sessionData['unionid'])? $sessionData['unionid'] : '';
            $data['loginip']   = $ip;
            $data['status']    = 'normal';
            $newuser = self::create($data);
            TokenService::cacheSession('',$data);
            return ['token'=>$data['token'],'wechat_miniapp_userid'=>$newuser->id];
        }else{         //刷新自定义登录态
            $oldToken = $user->token;
            $data['session_key'] = $user->session_key = isset($sessionData['session_key'])? $sessionData['session_key'] : '';
            $snowflake = new Snowflake;
            $data['token'] = $user->token = $snowflake->id();               //刷新自定义登录态
            $data['access_token_overtime'] = $user->access_token_overtime = time() + 3*24*3600; //和token字段生命周期相同
            $data['appid'] = $appid;
            $data['openid'] = $sessionData['openid'];
            $data['unionid'] = isset($sessionData['unionid'])? $sessionData['unionid'] : '';
            $user->save();
            TokenService::cacheSession($oldToken,$data);
            return ['token'=>$data['token'],'wechat_miniapp_userid'=>$user->id];
        }

    }

    //获取用户信息,只在前后端用户登录态都有效时调用，返回后台完整用户信息，不包括openid等敏感信息
    public function decryptData()
    {
        //获取用户SessionKey
        $token = input('token');
        $iv = input('iv');
        $encryptedData = input('encryptedData');
        $rawData = input('rawData');
        $signature = input('signature');
        $user = self::where('token' , $token)->find();               //用token获取用户帐号

        //数据签名校验
        $signature2 = sha1($rawData.$user['session_key']);   //用户表中的session_key
        //用户信息 解码
        if(true){  //$signature==$signature2  todo:先不校验签名了
            $encryptor = new Encryptor($user['appid']);
            $decryptData =  $encryptor->decryptData($user['session_key'],$iv,$encryptedData);
            $data = [
                'nickname'=>isset($decryptData['nickName'])?$decryptData['nickName']:'',
                'gender'=>isset($decryptData['gender'])?$decryptData['gender']:'',
                'language'=>isset($decryptData['language'])?$decryptData['language']:'',
                'city'=>isset($decryptData['city'])?$decryptData['city']:'',
                'province'=>isset($decryptData['province'])?$decryptData['province']:'',
                'country'=>isset($decryptData['country'])?$decryptData['country']:'',
                'avatarUrl'=>isset($decryptData['avatarUrl'])?$decryptData['avatarUrl']:'',
            ];
            $user->save($data);
            return $data;

        }else{
            return ['code'=>500,'msg'=>'更新失败'];
        }
    }

}